/*-
 * Copyright (c) 2006, 2007 FTS Team
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 4. Neither the name of the FTS Team nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *      DefaultRanker.hpp
 *
 * $FTS$
 */
#ifndef _DEFAULT_RANKER_HPP__
#define _DEFAULT_RANKER_HPP__ 1

/**
  @file DefaultRanker.hpp
  @brief Fulltext search document ranker
*/
#include <Ranker.hpp>
#include <RankedDocument.hpp>
#include <ZoneInfo.hpp>

namespace FTSS // FullTextSearchSystem
{

//FWD
class DocumentInfo;
class DocumentInfoStorage;
class DocumentStorage;
class IRConfig;
class InvIndexStorage;
class QueryWord;
class SnippetCollector;
class StopWords;
class TimeProfiler;

/**
  @class DefaultRanker DefaultRanker.hpp <DefaultRanker.hpp>
  @brief Document ranker
*/
class DefaultRanker:
  public Ranker
{
public:
	/**
	  @brief Constructor
	*/
	DefaultRanker();

	/**
	  @brief Set source data
	  @param oIConfig - Global configuration
	  @param pIStorage - Inverted index sorage
	  @param pIDocumentInfoStorage - Plain index storage
	*/
	void SetData(IRConfig             * oIConfig,
	             InvIndexStorage      * pIStorage,
	             DocumentInfoStorage  * pIDocumentInfoStorage);

	/**
	  @brief Rank documents
	  @param aDocuments - vector with documents to rank
	  @param iDocumentsToRank - number of documents in vector
	  @param dQuorumRank - minimum quorum rank
	  @param aAllWords - All query words
	  @param iTermsCount - Number of words in query
	  @param iMaxWordPos - max. word position in query
	  @param oSnippetCollector - snippet collector for search result
	  @param oTimeProfiler - Time profiler
	*/
	void Rank(DocumentEntry     ** aDocuments,
	          const UINT_32      & iDocumentsToRank,
	          const W_FLOAT      & dQuorumRank,
	          QueryWord          * aAllWords,
	          const UINT_32      & iTermsCount,
	          const UINT_32      & iMaxWordPos,
	          SnippetCollector   & oSnippetCollector,
	          TimeProfiler       & oTimeProfiler);

	/**
	  @brief A Destructor
	*/
	~DefaultRanker() throw();

private:
	/**
	  @struct RZone Ranker.hpp <Ranker.hpp>
	  @brief Document Zone with rank coefficients
	*/
	struct RZone:
	  public Zone
	{
		/** Passage Zone weight */
		W_FLOAT                passage_z;
		/** Term Zone weight    */
		W_FLOAT                tf_z;
	};

	/** Global configuration                                    */
	IRConfig            * pIRConfig;
	/** Data Storage                                            */
	InvIndexStorage     * pInvIndexStorage;
	/** Document properties database                            */
	DocumentInfoStorage * pDocumentInfoStorage;

	// Base points ///////////////////////////////////////////////
	//
	//
	/** Vector of base points                                   */
	WordEntryPos        * aBasePoints;
	/** Number of base points                                   */
	UINT_32               iBasePointsSize;
	/** Maximum size of vector                                  */
	UINT_32               iMaxBasePoints;

	// Ranks /////////////////////////////////////////////////////
	/** Okapi BM25 pair ranks                                   */
	W_FLOAT             * aOkapiPairRanks;
	/** Okapi BM25 ranks                                        */
	W_FLOAT             * aOkapiRanks;
	/** Current number of okapi ranks                           */
	UINT_32               iOkapiRanksSize;
	/** Max number of okapi ranks                               */
	UINT_32               iMaxOkapiRanks;


	// Configuration /////////////////////////////////////////////
	/** Number of zones                                         */
	INT_32                iZonesCount;
	/** Zone list                                               */
	RZone                 aZones[C_MAX_ZONES];
	/** Randomize coefficient                                   */
	W_FLOAT               dRandomizeC;

	// TF*IDF (Okapi BM25 with modifications) weighting //////////
	//
	//
	/** Contribution of okapi BM25 weight in full document rank */
	W_FLOAT               dRankTFIDFWeight;
	/** Weight of match form of word in query and in document,
	                                 in % of TF of ordinar word */
	W_FLOAT               dWordFormTFEQWeight;
	/** TF*IDF classic formula coefficient                      */
	W_FLOAT               dK;
	/** TF*IDF classic formula coefficient                      */
	W_FLOAT               dB;
	/** TF*IDF classic formula coefficient                      */
	W_FLOAT               dK1;
	/** TF*IDF classic formula coefficient                      */
	W_FLOAT               dK2;
	/** TF*IDF weigting norma                                   */
	W_FLOAT               dTFIDFWeightNorma;

	// Passage weighting /////////////////////////////////////////
	//
	//
	/** Contribution of passage weight in full document rank    */
	W_FLOAT               dRankPassageWeight;
	/** Penalty for incomplete passage                          */
	W_FLOAT               dIncompletePassagePenalty;
	/** Penalty for reverse order of words in document          */
	W_FLOAT               dOrderWeight;
	/** Penalty for passage length                              */
	W_FLOAT               dPassageLengthPenalty;
	/** Weight of match form of word in query and in passage,
	                                 in % of TF of ordinar word */
	W_FLOAT               dPassageWordFormEQWeight;
	/** Weight for for non-exact matched phrase                 */
	W_FLOAT               dPhraseMatchWeight;
	/** Weight for for exact matched phrase                     */
	W_FLOAT               dPhraseExactMatchWeight;
	/** Maximum passages in output                              */
	INT_32                iMaxPassages;
	/** Maximal length of passage                               */
	UINT_32               iMaxPassageLength;
	/** Normalization coefficient for passage weighting         */
	W_FLOAT               dPassageWeightNorma;

	// Passage weighting by position in document /////////////////
	//
	//
	/** Weighting coefficient, offset in x-axis                 */
	W_FLOAT               dMinXK;
	/** Scale coefficient, x-axis                               */
	W_FLOAT               dXK;
	/** Weighting coefficient, offset in y-axis                 */
	W_FLOAT               dMinYK;
	/** Scale coefficient, y-axis                               */
	W_FLOAT               dYK;

	// ///////////////////////////////////////////////////////////

	/**
	  @struct RankedDocumentSortLess DefaultRanker.hpp <DefaultRanker.hpp>
	  @brief Sorting functor
	*/
	struct RankedDocumentSortLess:
	  public STLW::binary_function<RankedDocument, RankedDocument, bool>
	{
		inline const bool operator()(const RankedDocument & x, const RankedDocument & y) const { return x.rank > y.rank; }
	};

	/**
	  @brief Get Document Entry by his document ID
	  @param iDocumentId - document ID [in]
	  @param iDocEntryPos - Start and end position to get [in/out]
	  @param vDocumentEntries - vector with document entries [in]
	  @return Pointer to the document entry or NULL if not found
	*/
	DocumentEntry * GetDocumentEntryById(const DocumentId_t             & iDocumentId,
	                                     UINT_32                        & iDocEntryPos,
	                                     STLW::vector<DocumentEntry *>  & vDocumentEntries);

	/*
	  @brief Create base points for specified document
	  @param iDocumentId - document ID [in]
	  @param aAllWords - all query words [in]
	  @param iTermsCount - number of words [in]
	*/
	void CreateBasePoints(const DocumentId_t  & iDocumentId,
	                      QueryWord           * aAllWords,
	                      const UINT_32       & iTermsCount);

	/**
	  @brief Construct and rank passages
	  @param aAllWords - all query words [in]
	  @param iMaxWordPos - max. word position in query [in]
	  @param dQuorumRank - quorum rank (min. passage rank) [in]
	  @param oRankedDocument - ranked document [in]
	  @param oTimeProfiler - Time profiler [in/out]
	  @return Best passage rank
	*/
	W_FLOAT ConstructAndRankPassages(QueryWord      * aAllWords,
	                                 const UINT_32  & iMaxWordPos,
	                                 const W_FLOAT  & dQuorumRank,
	                                 RankedDocument & oRankedDocument,
	                                 TimeProfiler   & oTimeProfiler);

	/**
	  @brief Rank current passage
	  @param aAllWords - all query words [in]
	  @param oCurrentPassage - passage to rank [in]
	  @param oTimeProfiler - Time profiler [in/out]
	  @return Passage rank
	*/
	W_FLOAT RankPassage(QueryWord     * aAllWords,
	                    Passage       & oCurrentPassage,
	                    TimeProfiler  & oTimeProfiler);

	/**
	  @brief Clear passage
	  @param oPassage - passage to clear [in/out]
	  @param iMaxPassageLength - max. length of passage [in]
	  @param iCurrQueryPos - current passage position [in]
	*/
	void ClearPassage(Passage        & oPassage,
	                  const UINT_32  & iMaxPassageLength,
	                  const UINT_32  & iCurrQueryPos);


	/**
	  @brief Get weight of passage by distance from start of document
	  @param iPos - position from start of document
	  @return passage weight
	*/
	W_FLOAT GetDistanceWeight(const UINT_32  & iPos);

	/**
	  @brief Rank document by classic Okapi BM25 formaula
	  @param iDocumentLength - length of document, in tokens [in]
	  @param aAllWords - all query words [in]
	  @param iMaxWordPos - max. word position in query [in]
	  @return Document Rank
	*/
	W_FLOAT RankByTFIDF(const UINT_32  & iDocumentLength,
	                    QueryWord      * aAllWords,
	                    const UINT_32  & iMaxWordPos);
#ifdef _DEBUG
	/**
	  @brief Print contents of passage
	  @param oPassage - passage to print [in]
	*/
	void PrintPassage(const Passage & oPassage);
#endif
};

} // namespace FTSS
#endif // _DEFAULT_RANKER_HPP__
// End.
